#ifndef PARALLELMPI2D_H
#define PARALLELMPI2D_H

#include <vector>
#include <string>

#include <mpi.h>

#include "../Parallel/ParallelMPI.h"

class Species;
class Grid2D;

class ParallelMPI2D : public ParallelMPI {
public:

    ParallelMPI2D(PicParams* params_, ParallelMPI* pmpi_);

    virtual ~ParallelMPI2D();

    //Create MPI communicator
    virtual void create_topology(PicParams* params);
    //Echanges particles of Species, list of particles comes frome Species::dynamics

    virtual void exchange_particles(Species* species, PicParams* params, int iDim);

    //create MPI_Dataype for Particle struct to exchange particles among MPI processors
    void create_particle_type();

    //Return coordinates in the cartesian MPI communicator
    //\param i direction
    inline int getProcCoord(int i) {
        return coords_[i];
    }
    //Return number of MPI process in the cartesian MPI communicator
    //\param i direction
    inline int getNbrOfProcs(int i) {
        return number_of_procs[i];
    }

    //Identify western MPI process, for boundary condition
    inline bool isWestern() {
        return ((coords_[0]==0)&&(periods_[0]==0));
    }
    //Identify eastern MPI process, for boundary condition
    inline bool isEastern() {
        return ((coords_[0]==number_of_procs[0]-1)&&(periods_[0]==0));
    }
    //Identify southern MPI process, for boundary condition
    inline bool isSouthern() {
        return ((coords_[1]==0)&&(periods_[1]==0));
    }
    //Identify northern MPI process, for boundary condition
    inline bool isNorthern() {
        return ((coords_[1]==number_of_procs[1]-1)&&(periods_[1]==0));
    }

    //Identify corner MPI ranks (2D, 2 sides)
    int extrem_ranks[2][2];

    void scatterGrid( Grid* grid );

    //gatherField0: values at the nodes, like electric field, electric potential
    virtual void gatherField0( Field<double>* field_global ,Field<double>* field  );
    //gatherField1: values at the nodes, like density
    virtual void gatherField1( Field<double>* field_global ,Field<double>* field  );
    //gatherField2: average values in the cells, like temperature, velocity
    virtual void gatherField2( Field<double>* field_global ,Field<double>* field  ){};
    //gatherField1_all: gather fields to all processes
    virtual void gatherField1_all( Field<double>* field_global ,Field<double>* field  );

    void scatterField( Field<double>* field_global ,Field<double>* field );
    


protected:

    MPI_Comm PMPI_COMM_2D;
};

#endif
